
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>锁的基本概念 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>锁的基本概念 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">在多线程环境中，锁机制的核心作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">锁机制能够保证在多线程环境中，在某一个时间点上，只能有一个线程进入临界区代码，从而保证临界区中操作数据的一致性。</div>
          </div>
          <div class="card-source">来源: 锁机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">乐观锁和悲观锁在处理并发问题时的核心思想有何不同？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">悲观锁总是假设会有其他线程修改数据，因此在操作数据前会先加锁。乐观锁则相反，它假设不会有并发冲突，操作时不加锁，只在更新数据时才检查在此期间数据是否被其他线程修改过。</div>
          </div>
          <div class="card-source">来源: 乐观锁/悲观锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">乐观锁常用的“数据版本机制”是如何实现的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">通常在数据表中增加一个版本号（version）字段。线程读取数据时一并读取version值。提交更新时，会检查当前数据库中的version值是否与之前读取到的version值相等。如果相等才执行更新，并将version值加一；否则，重试更新操作。</div>
          </div>
          <div class="card-source">来源: 乐观锁/悲观锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">比较</div>
          <div class="card-question">独享锁和共享锁的主要区别是什么？请以Java的ReadWriteLock为例说明。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">比较</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">独享锁一次只能被一个线程持有，而共享锁可以被多个线程同时持有。在Java的ReadWriteLock中，其写锁是独享锁，而读锁是共享锁，这可保证并发读是非常高效的。</div>
          </div>
          <div class="card-source">来源: 独享锁/共享锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">什么是可重入锁（递归锁）？它有什么主要优点？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可重入锁指的是同一个线程在外层方法获取锁之后，在进入内层方法时会自动获取锁，即同一个线程可以重复加锁。它的一个主要优点是可以一定程度上避免死锁。</div>
          </div>
          <div class="card-source">来源: 可重入锁/不可重入锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">可重入锁是如何通过计数器机制实现的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可重入锁通过一个计数器（count）来实现。当一个线程获取锁时，如果发现当前持有锁的就是自己，则会将计数器加1。每次释放锁时，计数器减1。只有当计数器减到0时，锁才会被真正释放，其他线程才能获取该锁。</div>
          </div>
          <div class="card-source">来源: 可重入锁/不可重入锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">比较</div>
          <div class="card-question">公平锁与非公平锁的主要区别是什么？非公平锁可能导致什么问题？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">比较</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">公平锁保证多个线程按照它们申请锁的顺序来获取锁。而非公平锁则不保证这个顺序，后申请的线程有可能比先申请的线程更早获取到锁。这可能会造成优先级反转或者饥饿现象。</div>
          </div>
          <div class="card-source">来源: 公平锁/非公平锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">分段锁的设计思想是什么？它如何提高并发性能？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">分段锁是一种细化锁粒度的设计。它不是对整个数据结构加锁，而是将其分成多个段（Segment），每个段都有自己的锁。当需要操作数据时，只对数据所在的那个段加锁。这样，只要多线程操作的数据不在同一个段中，它们就可以实现真正的并行插入，从而提高并发性能。</div>
          </div>
          <div class="card-source">来源: 分段锁/自旋锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">什么是自旋锁？它的优缺点分别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">自旋锁是指当一个线程尝试获取锁失败时，它不会立即进入阻塞状态，而是会采用循环的方式来不断尝试获取锁。其优点是减少了线程上下文切换带来的消耗，缺点是循环会持续消耗CPU资源。</div>
          </div>
          <div class="card-source">来源: 分段锁/自旋锁</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">AQS的核心思想是什么？当共享资源被占用时，它如何管理等待的线程？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">AQS的核心思想是：如果共享资源空闲，就将当前请求线程设置为工作线程并锁定资源。如果资源被占用，AQS会使用一个CLH队列锁机制，将暂时获取不到锁的线程封装成节点加入到一个先进先出（FIFO）的双向队列中进行等待。</div>
          </div>
          <div class="card-source">来源: CAS/AQS</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">CAS操作的全称是什么？它包含哪三个核心操作数？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">CAS全称为“比较并交换”（Compare And Swap）。它包含三个操作数：内存位置（V）、预期原值（A）和新值（B）。只有当内存位置V的值与预期原值A相匹配时，处理器才会自动将该位置的值更新为新值B。</div>
          </div>
          <div class="card-source">来源: CAS/AQS</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">问题</div>
          <div class="card-question">什么是CAS操作中的“ABA问题”？如何有效解决它？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">问题</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">ABA问题是指一个值在CAS操作期间，最初是A，被其他线程修改为B，然后又被改回了A。当执行CAS的线程检查时，发现值仍然是A，就错误地认为值没有被修改过。这个问题可以通过引入版本号来有效解决。</div>
          </div>
          <div class="card-source">来源: CAS/AQS</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
